home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
ICMPCMD.C
< prev
next >
Wrap
Text File
|
1993-08-09
|
13KB
|
451 lines
/* ICMP-related user commands */
#include <stdio.h>
#include "global.h"
#include "icmp.h"
#include "ip.h"
#include "mbuf.h"
#include "netuser.h"
#include "internet.h"
#include "timer.h"
#include "socket.h"
#include "proc.h"
#include "session.h"
#include "cmdparse.h"
#include "commands.h"
#include "tcp.h" /* used for rtt_add() */
#include "domain.h" /* used for autoping with domain-cache */
static void pingtx __ARGS((int s,void *ping1,void *p));
static void _setping(void *x);
int Icmp_trace = FALSE;
static int Icmp_echo = TRUE;
/* -------------------------- ICMP subcmds -------------------------------- */
static int
doicmpec(int argc,char **argv,void *p)
{
return setbool(&Icmp_echo,"ICMP echo response accept",argc,argv);
}
static int
doicmpstat(int argc,char **argv,void *p)
{
int i, j;
/* Note that the ICMP variables are shown in column order, because
* that lines up the In and Out variables on the same line
*/
for(j = i = 1; i <= NUMICMPMIB; i++) {
tprintf("(%2u)icmp%-16s%10lu%s",
i,
Icmp_mib[i].name,
Icmp_mib[i].value.integer,
(j++ % 2) ? " " : "\n");
}
if((j % 2) == 0) {
tputs("\n");
}
return 0;
}
static int
doicmptr(int argc,char **argv,void *p)
{
return setbool(&Icmp_trace,"ICMP trace",argc,argv);
}
int
doicmp(int argc,char **argv,void *p)
{
struct cmds Icmpcmds[] = {
"echo", doicmpec, 0, 0, NULLCHAR,
"status", doicmpstat, 0, 0, NULLCHAR,
"trace", doicmptr, 0, 0, NULLCHAR,
NULLCHAR
};
return subcmd(Icmpcmds,argc,argv,p);
}
/* ------------------------------------------------------------------------ */
/* Send ICMP Echo Request packets */
int
doping(int argc,char **argv,void *p)
{
struct proc *pinger = NULLPROC; /* Transmit process */
struct sockaddr_in from;
struct icmp icmp;
struct mbuf *bp;
int32 timestamp, rtt;
int s, fromlen;
struct ping ping;
struct session *sp;
memset(&ping,0,sizeof(struct ping));
if((ping.target = resolve(argv[1])) == 0) {
tprintf(Badhost,argv[1]);
return -1;
}
if((s = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) == -1) {
tputs(Nosocket);
return -1;
}
if(argc > 2) {
ping.len = (int16)min(atoi(argv[2]),1000);
}
if(argc < 4) {
/* One shot ping; let echo_proc hook handle response.
* An ID of MAXINT16 will not be confused with a legal socket
* number, which is used to identify repeated pings
*/
pingem(s,ping.target,0,MAXINT16,ping.len);
return 0;
}
ping.interval = atol(argv[3]) * 1000L;
/* Optionally ping a range of IP addresses */
if(argc > 4) {
ping.incflag = 1;
}
/* Allocate a session descriptor */
if((sp = ping.sp = newsession(argv[1],PING,0)) == NULLSESSION){
tputs(Nosess);
close_s(s);
return 1;
}
sp->s = s;
pinger = newproc("pingtx",768,pingtx,s,&ping,NULL,0);
/* Now collect the replies */
for(;;){
fromlen = sizeof(from);
if(recv_mbuf(s,&bp,0,(char *)&from,&fromlen) == -1) {
break;
}
ntohicmp(&icmp,&bp);
if(icmp.type != ICMP_ECHO_REPLY || icmp.args.echo.id != s) {
/* Ignore other people's responses */
free_p(bp);
continue;
}
/* ping.responses++; */
/* Get stamp */
if(pullup(&bp,(char *)×tamp,sizeof(timestamp)) != sizeof(timestamp)){
/* The timestamp is missing! */
free_p(bp); /* Probably not necessary */
continue;
}
free_p(bp);
/* Compute round trip time, update smoothed estimates */
rtt = msclock() - timestamp;
rtt_add(from.sin_addr.s_addr,(rtt * 3) / 2);
if(ping.incflag) {
tprintf("%s: rtt %lu\n",inet_ntoa(from.sin_addr.s_addr), rtt);
continue;
}
if(++ping.responses == 1){
/* First response, base entire SRTT on it */
ping.srtt = rtt;
ping.mdev = 0;
} else {
int32 abserr = (rtt > ping.srtt) ? (rtt-ping.srtt) : (ping.srtt-rtt);
ping.srtt = (7 * ping.srtt + rtt + 4) >> 3;
ping.mdev = (3 * ping.mdev + abserr + 2) >> 2;
}
}
if(pinger != NULLPROC) {
killproc(pinger);
}
keywait(NULLCHAR,1);
freesession(sp);
return 0;
}
void
echo_proc(int32 source,int32 dest,struct icmp *icmp,struct mbuf *bp)
{
int32 timestamp;
if(Icmp_echo && icmp->args.echo.id == MAXINT16
&& pullup(&bp,(char *)×tamp,sizeof(timestamp)) == sizeof(timestamp)) {
/* Compute round trip time */
int32 rtt = msclock() - timestamp;
tprintf("%s: rtt %lu\n",inet_ntoa(source),rtt);
rtt_add(source,(rtt * 3)/2);
}
free_p(bp);
}
/* Ping transmit process. Runs until killed */
static void
pingtx(int s,void *ping1,void *p)
{
struct ping *ping = (struct ping *)ping1;
if(ping->incflag) {
for(;;) {
tprintf("pinging %s...\n",inet_ntoa(ping->target));
pingem(s,ping->target++,0,(int16)s,ping->len);
pause(ping->interval);
}
} else {
tprintf("pinging %s...\n",inet_ntoa(ping->target));
ping->sent = 0;
for(;;) {
if(ping->sent) {
tprintf("sent%6lu rcvd%6lu %%%4lu avg rtt%6lu mdev%5lu\n",
ping->sent,
ping->responses,
(ping->responses * 100 + ping->sent / 2) / ping->sent,
ping->srtt,
ping->mdev);
}
pingem(s,ping->target,(int16)ping->sent++,(int16)s,ping->len);
pause(ping->interval);
}
}
}
/*----------------------------------------------------------------------*
* Send ICMP Echo Request packet *
*-----------------------------------------------------------------------*/
int /* DIALER requires a non-static definition */
pingem(
int s, /* Raw socket on which to send ping */
int32 target, /* Site to be pinged */
int16 seq, /* ICMP Echo Request sequence number */
int16 id, /* ICMP Echo Request ID */
int16 len) /* Length of optional data field */
{
struct mbuf *bp;
struct icmp icmp;
struct sockaddr_in to;
int32 clock = msclock();
struct mbuf *data = alloc_mbuf(len + sizeof(clock));
data->cnt = len + sizeof(clock);
/* Set optional data field, if any, to all 55's */
if(len == 64) {
char *cp = data->data + sizeof(clock), bits = 0x20;
while(bits < (0x20 + len)) {
*cp++ = bits++;
}
} else if(len != 0) {
memset(data->data + sizeof(clock),0x55,len);
}
/* Insert timestamp and build ICMP header */
memcpy(data->data,(char *)&clock,sizeof(clock));
icmpOutEchos++;
icmpOutMsgs++;
icmp.type = ICMP_ECHO;
icmp.code = 0;
icmp.args.echo.seq = seq;
icmp.args.echo.id = id;
bp = htonicmp(&icmp,data);
to.sin_family = AF_INET;
to.sin_addr.s_addr = target;
send_mbuf(s,bp,0,(char *)&to,SOCKSIZE);
return 0;
}
/*----------------------------------------------------------------------*
* provide a timer triggered ping to signal our presece to RPSF Servers *
* Syntax: *
* setping <address> <interval> *
*-----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*
*-----------------------------------------------------------------------*/
int
dosetping(int argc,char **argv, void *p)
{
int i;
int32 target, timeout;
Cache *ap = cache;
if(argc < 2) {
/*----------------------------------------------------------------*
* display the Pinglist *
*----------------------------------------------------------------*/
return docachelist(argc,argv,p);
}
if(argc < 3) {
/*----------------------------------------------------------------*
* give usage information *
*----------------------------------------------------------------*/
tputs("Usage: setping <address> <interval>\n");
return -1;
}
/*--------------------------------------------------------------------*
* resolve destination *
*--------------------------------------------------------------------*/
if((target = resolve(argv[1])) == 0) {
tprintf(Badhost,argv[1]); /* ain't never heard of */
return -1;
}
/*--------------------------------------------------------------------*
* allocate and fill a list entry *
*--------------------------------------------------------------------*/
for(i = 0; i < Dcache_size; i++) {
if(i == Dcache_size) {
return -1;
}
if(ap->address == target) {
break;
}
ap++;
}
if((timeout = atol(argv[2])) < 60) {
/* minimum interval is 60 seconds*/
timeout = 60L;
}
ap->timer.func = _setping; /* what to call on timeout */
ap->timer.arg = ap; /* dummy value */
set_timer(&ap->timer,timeout * 1000L); /* set timer duration */
#ifdef MDEBUG
sprintf(ap->timer.tname,"%.7s",argv[1]);
#endif
ap->state = Bad;
/*-------------------------------------------------------------------*
* just do a one shot ping and restart the timer *
*--------------------------------------------------------------------*/
if(ap->proc_run < Activep) {
_setping(ap);
}
return 0;
}
/*----------------------------------------------------------------------*
*-----------------------------------------------------------------------*/
int
doresetping(int argc,char **argv, void *p)
{
int i;
int32 target;
Cache *ap = cache;
if((target = resolve(argv[1])) == 0) {
tprintf(Badhost,argv[1]); /* ain't never heard of*/
return 1;
}
/*-------------------------------------------------------------------*
* isolate the entry *
* ap == entry to be removed *
*--------------------------------------------------------------------*/
for(i = 0; i < Dcache_size; i++) {
if(i == Dcache_size) {
return 1;
}
if(ap->address == target) {
break;
}
ap++;
}
if(ap->timer.state == TIMER_STOP) {
tprintf("Can't reset %s, autoping is active\n",argv[1]);
return 1;
}
stop_timer(&ap->timer);
ap->state = Unknown;
return 0;
}
static void autoping __ARGS((int a,void *p,void *v));
/*----------------------------------------------------------------------*
* this routine is called on each timeout *
*-----------------------------------------------------------------------*/
static void
_setping(void *x)
{
Cache *ap = x;
char name[22];
sprintf(name,"AP %s",inet_ntoa(ap->address));
/*-------------------------------------------------------------------*
* spawn an Autoping process *
*--------------------------------------------------------------------*/
ap->proc_run = Activep;
newproc(name,512,autoping,ap->state,x,NULL,0);
}
/*----------------------------------------------------------------------*
* process to be started for each Autoping *
* sorry, but that goto end thing is needed, cuz I have to reset the *
* 'proc_run" flag upon exit.. and won't leave that up to the optimizer. *
* DK5DC *
*-----------------------------------------------------------------------*/
static void
autoping(int oldstate,void *p,void *v)
{
Cache *ap = p;
struct sockaddr_in from;
struct mbuf *bp;
struct icmp icmp;
int s, fromlen = SOCKSIZE;
/*-------------------------------------------------------------------*
* get a socket
*--------------------------------------------------------------------*/
if((s = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) == -1){
tputs(Nosocket);
goto end1;
}
stop_timer(&ap->timer); /* stop the timer */
pingem(s,ap->address,0,s,64); /* fire up that ping */
/*-------------------------------------------------------------------*
* now wait and collect replies *
*--------------------------------------------------------------------*/
alarm(60000L); /* Let each ping timeout after 60 seconds*/
for(;;) {
if(recv_mbuf(s,&bp,0,(char *)&from,&fromlen) == -1){
if(errno == EALARM) /* We timed out */
break;
alarm(0);
/* ap->state = oldstate; */
goto end;
}
ntohicmp(&icmp,&bp);
free_p(bp);
if(icmp.type != ICMP_ECHO_REPLY
|| from.sin_addr.s_addr != ap->address
|| icmp.args.echo.id != s)
/* Ignore other people's responses */
continue;
alarm(0);
ap->state = Good; /* Finally change state */
goto end;
}
if(ap->state == Good) {
ap->state = Suspect;
} else if(ap->state == Suspect) {
ap->state = Bad;
}
end:
close_s(s);
end1:
start_timer(&ap->timer);
ap->proc_run = Waiting;
}